#pragma once

#include <iostream>
#include <functional>
#include <string>
#include <cassert>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"
#include "threadPool_singleton.hpp"
#include "Task.hpp"
#include "log.hpp"

// 使用线程池完成多线程收发的版本
class TcpServer
{

    static const int backlog = 32;
    static const size_t BUF_SIZE = 1024;
    using func_t = std::function<std::string(std::string)>;

public:
    TcpServer(func_t service, uint16_t svr_port)
        : _service(service), _svr_port(svr_port)
    {
    }

    void Initial()
    {
        // 1.创建套接字
        // if ((_sockfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) < 0) //accept非阻塞
        if ((_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            // std::cerr << "socket create fail: " << strerror(errno) << std::endl;
            LogMessage(FATAL, "socket create fail: %s\n", strerror(errno));
            exit(SOCKET_ERR);
        }
        LogMessage(TRACE, "socket create success: %s\n", strerror(errno));

        // 2.绑定服务器本地地址
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_svr_port);
        local.sin_addr.s_addr = INADDR_ANY;

        if (bind(_sockfd, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            // std::cerr << "bind fail: " << strerror(errno) << std::endl;
            LogMessage(FATAL, "bind fail: %s\n", strerror(errno));
            exit(BIND_ERR);
        }
        LogMessage(TRACE, "bind success: %s\n", strerror(errno));

        // 3.监听
        if (listen(_sockfd, backlog) < 0)
        {
            // std::cerr << "listen fail: " << strerror(errno) << std::endl;
            LogMessage(FATAL, "listen fail: %s\n", strerror(errno));
            exit(LISTEN_ERR);
        }
        LogMessage(TRACE, "listen success: %s\n", strerror(errno));
    }

    // 多线程版
    void Start()
    {
        LogMessage(TRACE, "server start!\n");
        while (true)
        {
            struct sockaddr_in client;
            bzero(&client, sizeof(client));
            socklen_t len = sizeof(client);

            // 1.接受监听的客户端
            int cfd = accept(_sockfd, (struct sockaddr *)&client, &len);
            if (cfd < 0)
            {
                // no client connect, continue try to accept
                LogMessage(WARNING, "accept fail: %s\n", strerror(errno));
                sleep(1);
                continue;
            }
            std::string client_info = std::string(inet_ntoa(client.sin_addr)) + "-" + std::to_string(ntohs(client.sin_port));
            // std::cout << "### 新用户已接入" << client_info << " cfd: " << cfd << " ###" << std::endl;
            LogMessage(INFO, "accept new client success:\n\t [%s] cfd is %d\n", client_info.c_str(), cfd);

            // 收发数据的工作交给新线程做，主线程只负责监听与接收客户端
            // 一个客户端创建一个服务线程
            // pthread_t pid;
            // pthread_create(&pid, nullptr, threadRoutine, new ThreadData(cfd, client_info, this));
            Task t(cfd, client_info,
                   std::bind(&TcpServer::ServerThreadRountine, this, std::placeholders::_1, std::placeholders::_2));
            threadPool<Task>::get_instance()->pushTask(t);
        }
    }

    void Recv(int cfd, const std::string &ci, std::string &respond, bool &quit)
    {
        // 读取客户端数据
        char buf[BUF_SIZE];
        memset(buf, 0, sizeof(buf));
        ssize_t n = read(cfd, buf, sizeof(buf) - 1);
        if (n < 0)
        {
            // read fail
            // std::cerr << "read from client fail: " << strerror(errno) << std::endl;
            // 此时用户不存在，无权close cfd
            LogMessage(ERROR, "read from client fail, client not exist: %s\n", strerror(errno));
            quit = true;
            return;
            // exit(RECV_ERR);
        }
        else if (n == 0)
        {
            // std::cout << ci << " client quit" << std::endl;
            LogMessage(WARNING, "client quit:\n\t [%s] cfd is %d\n", ci.c_str(), cfd);
            close(cfd);
            quit = true;
            return;
        }
        else
        {
            buf[n] = '\0';
            // std::cout << ci << " " << buf << std::endl;
            LogMessage(INFO, "[%s] %s\n", ci.c_str(), buf);
            respond = _service(buf);
        }
    }

    void Send(int cfd, const std::string &respond)
    {
        // 向客户端发回数据
        ssize_t n = write(cfd, respond.c_str(), respond.size());
        if (n < 0)
        {
            // write fail
            // std::cerr << "write to client fail: " << strerror(errno) << std::endl;
            LogMessage(ERROR, "write to client fail: %s\n", strerror(errno));
            // exit(WRITE_ERR);
        }
    }

    // task() -> 任务执行函数
    void ServerThreadRountine(int cfd, const std::string &client_info)
    {
        bool quit = false;   // 判断客户端是否已退出
        std::string respond; // 输出型参数
        while (true)
        {
            Recv(cfd, client_info, respond, quit);
            if (quit)
            {
                break;
            }
            Send(cfd, respond);
        }

        // bool quit = false;   // 判断客户端是否已退出
        // std::string respond; // 输出型参数
        // Recv(cfd, client_info, respond, quit);
        // if (quit)
        // {
        //     return;
        // }
        // Send(cfd, respond);
        // close(cfd);
    }

private:
    // static void *threadRoutine(void *args)
    // {
    //     ThreadData *td = static_cast<ThreadData *>(args);
    //     pthread_detach(pthread_self());
    //     while (true)
    //     {
    //         std::string respond = td->_ts->Recv(td->_cfd, td->_cinfo);
    //         td->_ts->Send(td->_cfd, respond);
    //     }
    // }

private:
    int _sockfd;        // 服务器的套接字文件描述符
    uint16_t _svr_port; // 服务器端口号
    func_t _service;    // 业务处理函数
};

// class TcpServer
// {
//     static const int backlog = 32;
//     static const size_t BUF_SIZE = 1024;
//     using func_t = std::function<std::string(std::string)>;

// public:
//     TcpServer(func_t service, uint16_t svr_port)
//         : _service(service), _svr_port(svr_port)
//     {
//     }

//     void Initial()
//     {
//         // 1.创建套接字
//         if ((_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
//         {
//             std::cerr << "socket create fail: " << strerror(errno) << std::endl;
//             exit(SOCKET_ERR);
//         }

//         // 2.绑定服务器本地地址
//         struct sockaddr_in local;
//         bzero(&local, sizeof(local));
//         local.sin_family = AF_INET;
//         local.sin_port = htons(_svr_port);
//         local.sin_addr.s_addr = INADDR_ANY;

//         if (bind(_sockfd, (struct sockaddr *)&local, sizeof(local)) < 0)
//         {
//             std::cerr << "bind fail: " << strerror(errno) << std::endl;
//             exit(BIND_ERR);
//         }

//         // 3.监听
//         if (listen(_sockfd, backlog) < 0)
//         {
//             std::cerr << "listen fail: " << strerror(errno) << std::endl;
//             exit(LISTEN_ERR);
//         }
//     }

//     // 多进程版
//     // void Start()
//     // {
//     //     signal(SIGCHLD, SIG_IGN);
//     //     while (true)
//     //     {
//     //         struct sockaddr_in client;
//     //         bzero(&client, sizeof(client));
//     //         socklen_t len = sizeof(client);

//     //         // 1.接受监听的客户端
//     //         int cfd = accept(_sockfd, (struct sockaddr *)&client, &len);
//     //         if (cfd < 0)
//     //         {
//     //             // no client connect, continue try to accept
//     //             continue;
//     //         }
//     //         std::string client_info = "[" + std::string(inet_ntoa(client.sin_addr)) + "-" + std::to_string(ntohs(client.sin_port)) + "]";

//     //         std::cout << "新用户已接入" << client_info << " cfd: " << cfd << std::endl;

//     //         // 2. 收发数据的工作交给子进程做，父进程只负责监听与接收客户端
//     //         pid_t id = fork();
//     //         assert(id >= 0);

//     //         if (id == 0)
//     //         {
//     //             while (true)
//     //             {
//     //                 std::string respond = Recv(cfd, client_info);
//     //                 Send(cfd, respond);
//     //             }
//     //         }
//     //         close(cfd);
//     //     }
//     // }

//     struct ThreadData
//     {
//         ThreadData() = default;

//         ThreadData(int cfd, std::string cinfo, TcpServer *ts)
//             : _cfd(cfd), _cinfo(cinfo), _ts(ts)
//         {
//         }

//         int _cfd;
//         std::string _cinfo;
//         TcpServer *_ts;
//     };
//     // 多线程版
//     void Start()
//     {
//         std::cout << "server start!" << std::endl;
//         while (true)
//         {
//             struct sockaddr_in client;
//             bzero(&client, sizeof(client));
//             socklen_t len = sizeof(client);

//             // 1.接受监听的客户端
//             int cfd = accept(_sockfd, (struct sockaddr *)&client, &len);
//             if (cfd < 0)
//             {
//                 // no client connect, continue try to accept
//                 continue;
//             }
//             std::string client_info = "[" + std::string(inet_ntoa(client.sin_addr)) + "-" + std::to_string(ntohs(client.sin_port)) + "]";
//             std::cout << "### 新用户已接入" << client_info << " cfd: " << cfd << " ###" << std::endl;

//             // 收发数据的工作交给新线程做，主线程只负责监听与接收客户端
//             // 一个客户端创建一个服务线程
//             pthread_t pid;
//             pthread_create(&pid, nullptr, threadRoutine, new ThreadData(cfd, client_info, this));
//         }
//     }

//     std::string Recv(int cfd, const std::string &ci)
//     {
//         // 读取客户端数据
//         char buf[BUF_SIZE];
//         memset(buf, 0, sizeof(buf));
//         std::string respond;
//         ssize_t n = read(cfd, buf, sizeof(buf) - 1);
//         if (n < 0)
//         {
//             // 读取失败，当前子执行流退出
//             std::cerr << "read from client fail: " << strerror(errno) << std::endl;

//             // exit(READ_ERR); // 多进程版
//             pthread_exit(nullptr);
//         }
//         else if (n == 0)
//         {
//             close(cfd);
//             // 多进程版可以不close，子进程exit也就回收了，对父进程没有影响
//             // 多线程版必须close，防止文件fd泄漏

//             // exit(0); // 多进程版
//             pthread_exit(nullptr);
//         }
//         else
//         {
//             // 读取成功，将数据业务处理后返回
//             buf[n] = '\0';
//             return _service(buf);
//         }
//     }

//     void Send(int cfd, std::string respond)
//     {
//         // 向客户端发回数据
//         ssize_t n = write(cfd, respond.c_str(), respond.size());
//         if (n < 0)
//         {
//             // write fail
//             std::cerr << "write to client fail: " << strerror(errno) << std::endl;
//             exit(WRITE_ERR);
//         }
//     }

// private:
//     static void *threadRoutine(void *args)
//     {
//         ThreadData *td = static_cast<ThreadData *>(args);
//         pthread_detach(pthread_self());
//         while (true)
//         {
//             std::string respond = td->_ts->Recv(td->_cfd, td->_cinfo);
//             td->_ts->Send(td->_cfd, respond);
//         }
//     }

// private:
//     int _sockfd;
//     uint16_t _svr_port;
//     func_t _service;
// };

